#ifndef PARADISOR_H
#define PARADISOR_H

#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/user.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <list>
#include <vector>
#include <algorithm>

using namespace std;

union I {
	uint64_t i64;
	uint32_t i32;
	uint16_t i16;
	uint8_t i8;
	char c[64];
};

/*A virtual memory range*/
struct Range
{
	pid_t pid;
	unsigned long start;
	unsigned long end;
};

/*A virtual memory address*/
struct Addr
{
	pid_t pid;
	unsigned long addr;
};

class ResultSet
{
	static int nextid;
	void init(void);
public:
	enum{
		FIND, /* This ResultSet is created by 'f' command. */
		INTERSECT, /* This ResultSet is created by intersecting two ResultSets. */
	};
	int id;
	int source;
	union{
		unsigned long long value;
		struct{
			int r1;
			int r2;
		};
	};
	int h, m; /* created time */
	struct Range *range;
	list<struct Addr> addrs;
	ResultSet(unsigned long long value);
	ResultSet(ResultSet *, ResultSet *);
	void add(unsigned long offset);
	void printinfo(void);
	void printaddrs(void);
};

/* defined in kernel-module */
enum {
	NO_TRACED_TASK = 1,
	CANNOT_WRITE_TO,
	CANNOT_WRITE_RESULT,
	TRY_COPY_SELF,
	TASK_NOT_STOPPED,
	NO_PRIVILEGE,
	NO_MM,
	NO_VMA,
	READ_KERNEL,
	TASK_NOT_TRACED,
	LEN_TOO_LONG,
	ADDR_NOT_ALIGNED,
	NO_PA,
	CANNOT_READ_FROM,
};

#ifndef SOURCE
extern pid_t traced_process;

extern list<struct Range> writablevma;
extern list<ResultSet *> results;
#endif

void getwritablevma(void);
int haswritablevma(void);
void printwritablevma(void);
void stoptask(void);
void continuetask(void);
void gettracedtasks(vector<long> *v);
int gettaskmem(struct Range* range, char **to);
void settaskmem(long pid, unsigned long addr, unsigned long long value, int len);
void searchtaskmem(unsigned long long value);
void traceme(void);
void startsubprocess(int argc, char *argv[]);
void listresultsets(void);
ResultSet * findresultset(int id);
int deleteresultset(int id);
/*
 * Return <0 if (a1.pid<a2.pid || (a1.pid==a2.pid && a1.addr<a2.addr) )
 */
int compareaddr(struct Addr *a1, struct Addr *a2);

void die(const char *perrormsg);
const char* errormsg(int result);
int minlen(unsigned long long value);
#endif
